6.2 Strings zerlegen
 
Der umgekehrte Schritt ist nicht ganz so einfach. Die Funktionen, mit denen Zeichenketten zerlegt werden können, sind nicht trivial.
Angenommen, wir haben eine Variable
Dim strText As String = "Apfelkuchen"
dann liefert
strText.Length
die Anzahl der Zeichen.
Abbildung 6.1
Der Text ist 11 Zeichen lang.
Ein bestimmtes Zeichen erhält man mit der Eigenschaft Chars. Achtung: Die Zählung beginnt bei 0! Um das »A« aus dem Text herauszulösen, wird also folgender Befehl benötigt:
strText.Chars(0)
Um ihn ganz korrekt weiterzuverarbeiten, muss noch die Methode ToString verwendet werden. Sollen mehrere Zeichen herausgelöst werden, dann so:
strText.Substring(2, 5)
Die überladene Methode Substring verlangt entweder nur die Position, ab welcher bis zum Ende herausgelöst werden soll, oder die Angabe, ab welcher Position bis zu welcher Position. Achtung: Die erste Zahl ist der Start-Index. Ab dieser Position wird herausgeschnitten. Jedoch beginnt die Zählung bei 0! Das obige Beispiel liefert deshalb »felku« und nicht »pfelk«.
Abbildung 6.2
strText.Substring(2, 5)
Das Gegenteil bewirkt IndexOf. Damit kann nach einer Zeichenkette gesucht werden. Die Funktion kann in der Form
strText.IndexOf("c")
geschrieben werden oder mit Parametern, die angeben, ab welcher Position und bis zu welcher gesucht werden soll. Achtung: Auch hier beginnt die Zählung wieder bei 0! strText.IndexOf("c") liefert folglich 7. strText.IndexOf("A") ergibt 0 und strText.IndexOf("x") gibt den Wert -1 zurück.
Analog arbeitet LastIndexOf - damit wird die Position des letzten gefundenen Zeichens ermittelt. Beispielsweise ergibt
strText.LastIndexOf("e")
die Zahl 9 (und nicht 3).
Abbildung 6.3
Man kann überprüfen, ob und wo ein Zeichen in einem String vorhanden ist.
Soll überprüft werden, ob eine Zeichenkette mit einem bestimmten Zeichen endet, dann existiert dafür die Methode EndsWith. Sie liefert »True« oder »False«. Im folgenden Fall ist »True« das Ergebnis:
strText.EndsWith("en")
Abbildung 6.4
Die Endung des Textes
Analog arbeitet die Funktion StartsWith. Sollen ein oder mehrere Zeichen ersetzt werden, so funktioniert dies mit der Methode Replace:
strText.Replace("kuchen", "torte")
... und schon gibt es »Apfeltorte«. Übrigens kann der »kuchen« gelöscht werden:
strText.Remove(5, 6)
Die erste Zahl gibt die Position an, ab der gelöscht wird, die zweite die Anzahl der Zeichen, die gelöscht werden sollen.
Stellen Sie sich eine Zeichenkette vor, die durch bestimmte Zeichen getrennt ist, beispielsweise ein Vor- und ein Zuname:
Dim strText As String = "Theodor W. Adorno"
Der Name soll in seine drei Einzelbestandteile zerlegt werden. Dazu wird ein Array benötigt, in welchem die einzelnen Elemente gespeichert werden können:
Dim strTeile() As String
Die umständliche Variante wäre, den Text Zeichen für Zeichen zu durchlaufen, an ein Feld zu übergeben und danach wieder zusammenzusetzen. Auch wenn es zwei einfache Befehle für diese Aufgabe gibt, so soll dennoch die komplizierte Variante auch gezeigt werden, da die Aufgabenstellung nicht immer so klar ist und man sich ab und zu mit komplexerem Code behelfen muss:
Dim intLetzte As Integer = 0
Dim j As Integer = 0
For i = 0 To strText.Length - 1
If strText.Substring(i, 1) = " " Then
ReDim Preserve strTeile(j)
strTeile(j) = _
strText.Substring(intLetzte, i - intLetzte) _
j += 1
intLetzte = i + 1
End If
Next
Eine Schleife läuft über alle Zeichen des eingegeben Texts und überprüft, ob es sich um ein Leerzeichen handelt. Falls ja (strText.Substring(i, 1) = " "), so wird das Datenfeld neu dimensioniert, wobei die schon vorhandenen Werte nicht gelöscht werden dürfen. Nun wird an das neue Datenfeld von der zuletzt gefundenen Position (intPosition) bis zur aktuellen alles an dieses neue Feld übergeben (strText.Substring(intLetzte, i - intLetzte)). Danach muss das Programm sich die aktuelle Position als letzte »merken«. Danach (oder schon davor) kann man über verschiedene Möglichkeiten prüfen, ob in dem Text überhaupt ein Leerzeichen war:
If j = 0 Then
MessageBox.Show _
("Es existiert kein Leerzeichen in """ & _
strText & """.")
Exit Sub
Falls doch, so wird auch noch der letzte Teil übergeben:
Else
ReDim Preserve strTeile(j)
strTeile(j) = strText.Substring(intLetzte)
End If
strText = ""
Das letzte Datenfeld erhält den »Rest«: strTeile(j) =
strText.Substring(intLetzte).
Mit einer Schleife können alle Elemente durchlaufen werden. Die Anzahl der Datensätze des Arrays wird über Length ermittelt, da uns ein eindimensionales Datenfeld vorliegt:
Dim i As Integer
For i = 0 To strTeile.Length - 1
strText = strText & "/" & strTeile(i)
Next
Abbildung 6.5
Das Zerlegen funktioniert.
Abbildung 6.6
Das Überprüfen klappt auch.
Die Funktionen Join und Split leisten das Gleiche. Für unser Beispiel sieht das wie folgt aus:
strTeile = strText.Split(" ")
strText = strText.Join("/", strTeile)
Abbildung 6.7
Mehrere Leerzeichen hintereinander werden als Trennzeichen wahrgenommen.
Die Methoden Trim, TrimEnd und TrimStart löschen Leerzeichen am Anfang und/oder am Ende der Zeichenkette.
Schließlich halte ich die beiden Funktionen ToLower und ToUpper für wichtig. Mit ihrer Hilfe kann ein Text in Groß- oder Kleinbuchstaben verwandelt werden.
Dies sind alles lustige Funktionen, allerdings stellt sich Frage, wer denn so etwas braucht. Hierzu ein paar Beispiele, die den Gebrauch veranschaulichen.
Die Funktion Trim verwende ich immer, um sicherzustellen, dass der Anwender kein Leerzeichen vor oder nach der Eingabe getippt hat. Es gibt Benutzer, die schreiben Text in eine Combobox (obwohl man ihn auswählen könnte) und beenden die Eingabe mit einem Leerzeichen. Damit steht beispielsweise nicht mehr »München«, sondern »München « im Kombinationsfeld, was als zwei verschiedene Orte interpretiert und verarbeitet wird.
In einem Textfeld stehen Vor- und Zunamen. Sie sollten getrennt werden. Dafür ist die Funktion Split zuständig. Oder etwas eleganter: Zuerst werden die Leerzeichen davor und danach entfernt:
Dim strText As String = Me.txtName.Text
strText = strText.Trim
Dann wird überprüft, ob kein Leerzeichen im Namen vorkommt:
If strText.IndexOf(" ") = -1 Then
MessageBox.Show("Der Name lautet: " & _
strText)
Else
...
Bei zwei oder mehr Bestandteilen wird mit Split zerlegt:
strTeile = strText.Split(" ")
Nun werden der zweite bis n-2-te Teil eingesammelt und beschriftet mit: »Der 2. Vorname lautet:«, »Der 3. Vorname lautet:« ... Sollte es nur zwei Bestandteile geben, dann wird die Schleife übergangen - dann läuft sie von 2 bis 1.
Dim strAnzeige As String
strText = Me.txtName.Text
strTeile = strText.Split(" ")
For i = 1 To strTeile.Length - 2
strAnzeige = strAnzeige & "Der " & _
(i + 1).ToString & ". Vorname lautet: " & _
strTeile(i) & vbCr _
Next
MessageBox.Show("Der Vorname lautet: " & _
strTeile(0) & vbCr & _
strAnzeige & "Der Zuname lautet: " & _
strTeile(strTeile.Length - 1))
Abbildung 6.8
Eine andere Zerlegung
Mit diesen Funktionen kann überprüft werden, ob in einem Eingabefeld für die E-Mail-Adresse ein Punkt und ein »@« eingegeben wurden oder ob im Postleitzahlenfeld nur vier- oder fünfstellige Zahlen stehen. Manche Systeme liefern auch vor und hinter den Daten Anführungsstriche. Diese müssen entfernt werden. Oder, und damit sind wir wieder bei unserem Thema: Beim Zugriff auf Dateien.
Angenommen, zwei Dateinamen werden überprüft, dann kann es vorkommen, dass sie in unterschiedlicher Schreibweise vorliegen - der eine in Großbuchstaben, der andere in Groß-/Kleinschreibung. Deshalb kann man mit den Methoden ToLower und ToUpper die Schreibweise in Groß- oder Kleinbuchstaben drehen. Und damit sind sie vergleichbar.
Bei einem Pfad soll überprüft werden, ob das letzte Zeichen ein »\« ist. Falls nicht, soll einer angehängt werden, damit der Dateiname hinzugefügt werden kann. Also wird überprüft:
If strPfad.EndsWiths("\") = False Then
strPfad &= "\"
End If
strDateiNameGanz = strPfad & strDateiName
Oder aus einem Dateinamen mit Pfadangabe soll der Dateiname herausgelöst werden:
Dim strTeile() As String
strDateiNameGanz = "C:\Eigene Dateien\Test\WW\Versuch.doc"
strTeile = strDateiNameGanz.Split("\")
Damit kann der Dateiname ermittelt werden:
strTeile(strTeile.Length -1)
Andere Variante: Der Dateiname wird ohne Endung angezeigt. Dazu wird die Position des Punktes ermittelt und bis zu dieser Position abgeschnitten:
strDN = strTeile(Length -1)
strDN = strDN.Substring(0, strDN.IndexOf("."))
Das folgende Beispiel verdeutlicht es. In einer Listbox sollen alle Dateinamen von Dateien aufgelistet werden, die sich in einem Ordner befinden:
Dim i As Integer
Dim objDateien() As System.IO.FileInfo
objDateien = New _
DirectoryInfo("C:\Eigene Dateien").GetFiles()
For i = 0 To objDateien.GetUpperBound(0)
Me.lstDateien.Items.Add _
(ObjDateien(i).ToString)
Next
Soll die Endung nicht angezeigt werden, dann ist die Schleife wie oben beschrieben zu modifizieren:
Dim strDN As String
For i = 0 To objDateien.Length -1
strDN = ObjDateien(i).ToString
strDN = strDN.Substring(0, _
strDN.LastIndexOf("."))
Me.lstDateien.Items.Add(strDN)
Next
Beachten Sie, dass ich mit der Methode LastIndexOf und nicht IndexOf gearbeitet habe. Denn wenn eine Datei einen weiteren Punkt im Dateinamen hätte, so würde ab diesem Punkt der übrige Text abgeschnitten.
Leider stellt die Methode GetFiles keinen Parameter zur Verfügung, mit dem nicht nur das angegebene Verzeichnis durchsucht wird, sondern auch alle Unterverzeichnisse. Deshalb müssen mit einer Schleife alle Unterverzeichnisse durchlaufen und von jedem gefundenen Verzeichnis die Dateien ausgelesen werden. Die Prozedur, die dies leistet, könnte wie folgt aussehen:
Sub DateienAuflisten(ByVal strOrdner As String)
Dim objDateien() As System.IO.FileInfo
Dim i As Integer
Dim strDN As String
objDateien = New DirectoryInfo(strOrdner). _
GetFiles()
For i = 0 To objDateien.GetUpperBound(0)
strDN = ObjDateien(i).ToString
strDN = strDN.Substring(0, strDN.IndexOf("."))
Me.lstDateien.Items.Add(strDN)
Next
End Sub
Ein Ordner wird in dieser Prozedur vom Typ String übergeben. Aus diesem Ordner werden alle darin befindlichen Dateien ausgelesen und in einem Array gespeichert. Eine Schleife durchläuft diese Liste, streicht die Endungen weg und zeigt sie in der Listbox an. Die Prozedur könnte folgendermaßen aufgerufen werden:
Dim objOrdner() As System.IO.DirectoryInfo
Dim i As Integer
objOrdner = New DirectoryInfo("C:\Eigene Dateien"). _
GetDirectories()
For i = 0 To objOrdner.Length -1
DateienAuflisten("C:\Eigene Dateien" & _
objOrdner.(i).ToString)
Next
Einen kleinen Schönheitsfehler hat diese Prozedur. Der Array objOrdner sammelt alle Verzeichnisse aus C:\Eigene Dateien ein und übergibt sie an die Prozedur DateienAuflisten. Dabei fehlen nun allerdings die Dateien aus C:\Eigene Dateien. Man könnte sie ebenfalls in die Liste aufnehmen lassen, indem man vor oder nach der Schleife den Befehl setzt:
DateienAuflisten("C:\Eigene Dateien")
Und die Unterverzeichnisse? Das wird ein bisschen kompliziert, weil nicht bekannt ist, wie viele Ebenen abgearbeitet werden müssen. Deshalb muss man eine Prozedur schreiben, die sich so lange selbst aufruft, bis alle Unterverzeichnisse ausgelesen sind. Die Prozedur DateienAuflisten bleibt unverändert. Die Prozedur, die sich selbst aufruft, könnte so aussehen:
Private Sub OrdnerSuchen(ByVal objOrdner As _
System.IO.DirectoryInfo)
Dim i As Integer
Dim objOrdnerListe() As System.IO.DirectoryInfo
DateienAuflisten(objOrdner.FullName)
objOrdnerListe = objOrdner.GetDirectories
If objOrdnerListe.GetUpperBound(0) > 0 Then
For i = 0 To objOrdnerListe.GetUpperBound(0)
OrdnerSuchen(objOrdnerListe(i))
Next
End If
End Sub
Das Prinzip ist einfach: Es wird überprüft, ob sich weitere Unterordner im aktuellen Ordner befinden. Falls ja, dann wird jeder einzelne genommen und das Programm OrdnerSuchen erneut aufgerufen. Denn diese Prozedur ruft DateienAuflisten auf. Beachten Sie, dass nun mit der Eigenschaft FullName gearbeitet wurde, sonst funktioniert das Programm nicht.
Das Programm OrdnerSuchen könnte wiederum beim Starten der Form so aufgerufen werden:
Dim objOrdner() As System.IO.DirectoryInfo
Dim i As Integer
objOrdner = New DirectoryInfo("C:\Eigene Dateien"). _
GetDirectories()
DateienAuflisten("C:\Eigene Dateien")
For i = 0 To objOrdner.Lentgh - 1
OrdnerSuchen(objOrdner(i))
Next
Abbildung 6.9
Die Liste der Dateinamen
Um dem Ganzen noch eines aufzusetzen, soll gleichzeitig der Pfad gespeichert werden. Der Grund? Angenommen, dies ist eine Liste von Dateien, von denen der Benutzer eine auswählt, die anschließend geöffnet wird. Da die Dateien in unterschiedlichen Ordnern liegen, kann nicht einfach ein Ordnername mit dem ausgewählten Text verkettet werden. Mit einem kleinen Trick gelingt es dennoch. Beim Füllen der Liste mit Dateinamen läuft ein Zähler mit, der ein Datenfeld vergrößert. In diesem Datenfeld werden die Pfade, das heißt die vollständigen Dateinamen, gespeichert. Es werden global deklariert:
Dim intDateienZähler As Integer
Dim strPfad() As String
In der Prozedur DateienAuflisten vor oder nach dem Eintragen in die Liste (Add) wird der ganze Dateiname im Array gespeichert:
ReDim Preserve strPfad(intDateienZähler)
strPfad(intDateienZähler) = _
objDateien(i).FullName
intDateienZähler += 1
Beim Laden der Form wurde intDateienZähler auf 0 gesetzt. Und angezeigt wird der Pfad im Label txtDateiName:
Private Sub lstDatei_SelectedIndexChanged(ByVal sender As _
System.Object, ByVal e As System.EventArgs) Handles _
lstDatei. SelectedIndexChanged
Me.txtDateiName.Text = strPfad(Me.lstDatei.SelectedIndex)
End Sub
Dies funktioniert, weil beide Listen bei 0 zu zählen beginnen.
Abbildung 6.10
Die Liste mit komplettem Dateinamen
Die folgende Tabelle listet die wichtigsten String-Funktionen auf:
Tabelle 6.1
Die wichtigsten String-Funktionen
| Methode
|
Bedeutung
|
| Length
|
die Anzahl der Zeichen
|
| Compare
|
vergleicht zwei Zeichenketten miteinander
|
| EndsWith
|
endet mit einer Zeichenkette
|
| StartsWith
|
beginnt mit einer Zeichenkette
|
| IndexOf
|
ermittelt die Position eines Zeichens oder einer Zeichenkette in einer anderen
|
| LastIndexOf
|
ermittelt die letzte Position eines Zeichens oder einer Zeichenkette in einer anderen
|
| Insert
|
fügt eine Zeichenkette in eine andere ein
|
| Remove
|
löscht Zeichen in einer Zeichenkette
|
| Replace
|
ersetzt Zeichen in einer Zeichenkette
|
| Substring
|
schneidet ab einer bestimmten Position Zeichen aus einer Zeichenkette heraus
|
| Split
|
zerlegt eine Zeichenkette
|
| Join
|
fügt die Elemente eines Arrays zu einer Zeichenkette zusammen
|
| PadLeft
|
füllt von links mit Leerzeichen auf
|
| PadRight
|
füllt von rechts mit Leerzeichen auf
|
| Trim
|
löscht Leerzeichen vor und nach der Zeichenkette
|
| TrimEnd
|
löscht Leerzeichen nach der Zeichenkette
|
| TrimStart
|
löscht Leerzeichen vor der Zeichenkette
|
| ToLower
|
wandelt in Kleinbuchstaben um
|
| ToUpper
|
wandelt in Großbuchstaben um
|
|